﻿using System;
using System.Collections.Generic;
using System.Text;
using Autofac;
using PlutoStudio.Dependency;
using PlutoStudio.Configuration.Startup;
using Autofac.Core;
using PlutoStudio.Events.Bus.Handlers;
using PlutoStudio.Events.Bus.Factories;

namespace PlutoStudio.Events.Bus
{
    internal class EventBusInstaller:IocInstaller
    {
        private readonly IIocResolver _iocResolver;
        private readonly IEventBusConfiguration _eventBusConfiguration;
        private IEventBus _eventBus;

        public EventBusInstaller(IIocResolver iocResolver)
        {
            _iocResolver = iocResolver;
            _eventBusConfiguration = _iocResolver.Resolve<IEventBusConfiguration>();
        }

        protected override void Load(ContainerBuilder builder)
        {
            if (_eventBusConfiguration.UseDefaultEventBus)
            {
                builder.Register(f => EventBus.Default).As<IEventBus>().SingleInstance();
            }
            else
            {
                builder.RegisterType<EventBus>().As<IEventBus>().SingleInstance();
            }
            base.Load(builder);
        }

        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
        {
            var eventBus = _eventBus ?? (_eventBus = _iocResolver.Resolve<IEventBus>());
            if (!typeof(IEventHandler).IsAssignableFrom(registration.Activator.LimitType))
            {
                return;
            }

            var interfaces = registration.Activator.LimitType.GetInterfaces();
            foreach (var @interface in interfaces)
            {
                if (!typeof(IEventHandler).IsAssignableFrom(@interface))
                {
                    continue;
                }

                var genericArgs = @interface.GetGenericArguments();
                if (genericArgs.Length == 1)
                {
                    _eventBus.Register(genericArgs[0], new IocHandlerFactory(_iocResolver, registration.Activator.LimitType));
                }
            }
            base.AttachToComponentRegistration(componentRegistry, registration);
        }
    }
}
